<?php

/**
 * mysqli实例驱动
 */

class APF_Mysqli extends DB
{
    var $link_id   = NULL;

    var $settings  = '';
    var $charset   = 'utf8';

    var $starttime = 0;
    var $version   = '';
    var $dbhash    = '';

    public function __construct($settings, $charset = 'utf8', $quiet_mode = false)
    {
        $this->parseSettings($settings);

        $this->charset = $charset;

        if ($quiet_mode !== false)
        {
            $this->connect(true, $quiet_mode);
        }

        start_performance();
    }

    public function __destruct()
    {
        $this->close();
    }

    public function parseSettings($settings)
    {
        $this->settings = $settings;
    }

    private function connect($select_db = true, $quiet_mode = false)
    {
        $set = @parse_url($this->settings);

        if (isset($set['port']) == false)
        {
            $set['port'] = '3306';
        }

        if (isset($set['query']) == false)
        {
            $set['query'] = '';
        }

        if ($select_db === true)
        {
            $this->link_id = @mysqli_connect($set['host'], $set['user'], $set['pass'], $set['query'], $set['port']);
        }
        else
        {
            $this->link_id = @mysqli_connect($set['host'], $set['user'], $set['pass'], '', $set['port']);
        }

        if ($this->link_id === false)
        {
            if ($quiet_mode === false)
            {
                trigger_error("[MYSQL] 不能连接数据库, HOST: " . $set['host'] . ':' . $set['port'] . ", USER: " . $set['user'] . ", 错误信息: " . mysqli_connect_error(). ", 错误代码: " . mysqli_connect_errno(), E_USER_ERROR);
            }

            return false;
        }

        $this->dbhash    = md5($set['host'] . ':' . $set['port'] . $set['user'] . $set['pass']);
        $this->version   = mysqli_get_server_info($this->link_id);
        $this->starttime = time();

        /* 如果mysql 版本是 4.1+ 以上，需要对字符集进行初始化 */
        if ($this->version > '4.1')
        {
            mysqli_set_charset($this->link_id, $this->charset);
            /* 在 my.cnf 中已经声明，如果没有声明需要加入并更改以下代码 */
/*
            if ($this->version > '5.0.1')
            {
                mysqli_query($this->link_id, "SET sql_mode=''");
            }
*/
        }

        return true;
    }

    public function select_database($dbname)
    {
        if ($this->link_id === NULL)
        {
            $this->connect(false);
        }

        return mysqli_select_db($this->link_id, $dbname);
    }

    public function set_charset($charset)
    {
        /* 如果mysql 版本是 4.1+ 以上，需要对字符集进行初始化 */
        if ($this->version > '4.1')
        {
            if (in_array(strtolower($charset), array('gbk', 'big-5', 'big5', 'utf-8', 'utf8')))
            {
                $charset = str_replace('-', '', $charset);
            }
            mysqli_set_charset($this->link_id, $charset);
        }

        $this->charset = $charset;
    }

    public function fetch_array($query, $result_type = MYSQLI_ASSOC)
    {
        return mysqli_fetch_array($query, $result_type);
    }

    public function query($sql, $quiet_mode = false)
    {
        if (isset($GLOBALS['_PERFORMANCE']->MYSQL['COUNT']) === true)
        {
            ++$GLOBALS['_PERFORMANCE']->MYSQL['COUNT'];

            if ($GLOBALS['_PERFORMANCE']->MYSQL['COUNT'] <= 199)
            {
                $GLOBALS['_PERFORMANCE']->DETAIL[] = 'MYSQL-> ' . $sql;
            }
        }
        else
        {
            $GLOBALS['_PERFORMANCE']->MYSQL['COUNT'] = 1;
            $GLOBALS['_PERFORMANCE']->DETAIL[] = 'MYSQL-> ' . $sql;
        }

        if ($this->link_id === NULL)
        {
            $this->connect();
        }

        /* 当当前的时间大于类初始化时间的时候 + 5s，自动执行 ping 这个自动重新连接操作 */
        if (time() > $this->starttime + 5)
        {
            if (mysqli_ping($this->link_id) === false)
            {
                @mysqli_close($this->link_id);

                $this->connect();
            }
        }

        $explain_time = microtime(true);
        if (!($query = mysqli_query($this->link_id, $sql)))
        {
            if ($quiet_mode === false)
            {
                trigger_error("[MYSQL] SERVER_GROUP " . SERVER_GROUP . " -->$sql<-- 执行出错, 错误信息: " . mysqli_error($this->link_id). ", 错误代码: " . mysqli_errno($this->link_id), E_USER_WARNING);
            }

            return false;
        }
        $explain_time = microtime(true) - $explain_time;
        if ($explain_time > 0.100)
        {
            // 记慢查询
        }

        return $query;
    }

    public function affected_rows()
    {
        return mysqli_affected_rows($this->link_id);
    }

    public function error()
    {
        return mysqli_error($this->link_id);
    }

    public function errno()
    {
        return mysqli_errno($this->link_id);
    }

    public function result($query, $row)
    {
        return @mysqli_result($query, $row);
    }

    public function num_rows($query)
    {
        return mysqli_num_rows($query);
    }

    public function num_fields($query)
    {
        return mysqli_num_fields($query);
    }

    public function free_result($query)
    {
        return mysqli_free_result($query);
    }

    public function insert_id()
    {
        $id = (float)mysqli_insert_id($this->link_id);

        /* 在 mysqli 方式下，也许不需要了，请看 mysqli_insert_id 文档 */
        if ($id < 0)
        {
            $id = (float)$this->getOne('SELECT last_insert_id()');
        }

        return $id;
    }

    public function fetchRow($query)
    {
        return mysqli_fetch_assoc($query);
    }

    public function fetch_fields($query)
    {
        return mysqli_fetch_field($query);
    }

    public function version()
    {
        return $this->version;
    }

    public function ping()
    {
        return mysqli_ping($this->link_id);
    }

    public function escape_string($string)
    {
        if ($this->link_id === NULL)
        {
            $this->connect();
        }

        return mysqli_real_escape_string($this->link_id, $string);
    }

    public function close()
    {
        if ($this->link_id !== NULL)
        {
            $result = @mysqli_close($this->link_id);
        }
        else
        {
            $result = true;
        }

        $this->link_id  = NULL;
        $this->settings = array();
        $this->charset  = 'utf8';

        return $result;
    }

    public function getDesc($table, $all, $cache_time = 5)
    {
        static $table_desc = array();

        if (isset($table_desc[$this->settings][$table]) === true)
        {
            $field_descs = $table_desc[$this->settings][$table];
        }
        else
        {
            if ($cache_time > 0)
            {
                $field_descs = xc_get('getdesc_' . $this->settings, $table);
                if ($field_descs === false)
                {
                    $field_descs = $this->getAll('DESC ' . $table);
                    if ($field_descs !== false)
                    {
                        xc_set('getdesc_' . $this->settings, $table, $field_descs, $cache_time);
                        $table_desc[$this->settings][$table] = $field_descs;
                    }
                }
            }
            else
            {
                $field_descs = $this->getAll('DESC ' . $table);
                if ($field_descs !== false)
                {
                    $table_desc[$this->settings][$table] = $field_descs;
                }
            }
        }

        if ($all === true)
        {
            return $field_descs;
        }
        else
        {
            $array = array();
            foreach ($field_descs AS $value)
            {
                $array[] = $value['Field'];
            }

            return $array;
        }
    }

/*
+---------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-----------------+----------+----------------+---------+
| Name          | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time          | Collation       | Checksum | Create_options | Comment |
+---------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-----------------+----------+----------------+---------+
| page_settings | MyISAM |      10 | Dynamic    |    1 |            160 |         160 | 281474976710655 |         5120 |         0 |              2 | 2008-11-10 21:33:43 | 2008-11-11 15:56:12 | 2008-11-10 21:33:44 | utf8_general_ci |     NULL |                |         |
+---------------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-----------------+----------+----------------+---------+
*/
    public function getBestTableByStatus($tables, $cache_time = 5)
    {
        static $table_status = array();

        $compare_tables = $rows = $lengths = array();
        foreach($tables AS $table => $setting)
        {
            if (isset($table_status[$setting]) === false)
            {
                if ($cache_time > 0)
                {
                    $status = xc_get('getbesttable_', $setting);
                    if ($status === false)
                    {
                        $set = @parse_url($setting);
                        dbserver_connect($setting);

                        $status = $this->getAll("SHOW TABLE STATUS FROM `" . $set['query'] . "`");
                        if ($status !== false)
                        {
                            xc_set('getbesttable_', $setting, $status, $cache_time);
                            $table_status[$setting] = $status;
                        }
                    }
                }
                else
                {
                    $set = @parse_url($setting);
                    dbserver_connect($setting);

                    $status = $this->getAll("SHOW TABLE STATUS FROM `" . $set['query'] . "`");
                    if ($status !== false)
                    {
                        $table_status[$setting] = $status;
                    }
                }
            }

            foreach($status AS $value)
            {
                if ($value['Name'] === $table)
                {
                    $rows[$table]           = $value['Rows'];
                    $lengths[$table]        = $value['Data_length'];

                    $compare_tables[$table] = $value;
                }
            }
        }

        array_multisort($lengths, SORT_ASC, $rows, SORT_ASC, $compare_tables);

        return reset($compare_tables);
    }

    public function getOne($sql)
    {
        $sql = trim($sql . ' LIMIT 1');

        $res = $this->query($sql);
        if ($res !== false)
        {
            $row = mysqli_fetch_row($res);

            if ($row !== NULL)
            {
                return $row[0];
            }
            else
            {
                return '';
            }
        }
        else
        {
            return false;
        }
    }

    public function getAll($sql)
    {
        $res = $this->query($sql);
        if ($res !== false)
        {
            $array = array();
            while ($row = mysqli_fetch_assoc($res))
            {
                if ($row === NULL)
                {
                    $array[] = array();
                }
                else
                {
                    $array[] = $row;
                }
            }

            return $array;
        }
        else
        {
            return false;
        }
    }

    public function getRow($sql)
    {
        $sql = trim($sql . ' LIMIT 1');

        $res = $this->query($sql);
        if ($res !== false)
        {
            $result = mysqli_fetch_assoc($res);
            if ($result === NULL)
            {
                return array();
            }
            else
            {
                return $result;
            }
        }
        else
        {
            return false;
        }
    }

    public function getCol($sql)
    {
        $res = $this->query($sql);
        if ($res !== false)
        {
            $array = array();
            while ($row = mysqli_fetch_row($res))
            {
                if ($row === NULL)
                {
                    $array[] = '';
                }
                else
                {
                    $array[] = $row[0];
                }
            }

            return $array;
        }
        else
        {
            return false;
        }
    }

}

?>